#pragma once

//守护进程化（Daemonization）是指将一个普通进程转变为守护进程（daemon）的过程。守护进程是在后台运行的一种特殊进程，
//它独立于控制终端，通常在系统启动时运行，直到系统关闭时才结束。守护进程通常用于提供系统服务，如Web服务器、数据库服务器等。
//脱离终端控制：不受用户登录/注销影响
//独立运行：没有控制终端（Controlling Terminal）
//后台服务：提供系统级或网络服务
//生命周期长：通常从系统启动运行到系统关闭
//环境隔离：与启动环境完全分离

//nochdir=0：自动切换到根目录
//noclose=0：自动重定向标准流到/dev/null

//nochdir=1:不更改工作目录，保持当前工作目录
//noclose=1:不关闭和重定向标准流，保持它们打开
#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"
#include "Common.hpp"

using namespace LogModule;
const std::string dev = "/dev/null";


//将服务守护进程化的服务

void Daemon(int nochair,int noclose)
{
    //1.忽略IO,子进程退出等相关的信号
    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);

    //2.父进程直接退出
    if(fork()>0)
    exit(0);
    
    //3.只能是子进程 成为了孤儿 子进程由init进程接管 父进程就是1
    setsid();//成为一个独立的会话 使子进程脱离原会话、原进程组、原控制终端
    
    //再次创建子进程并退出：这一步不是必须的，但可以确保进程不再是会话领头进程，从而防止其再次获得控制终端（根据System V规范）。
    // 步骤3: (可选但推荐) 二次fork确保不是会话首进程
    // pid = fork();
    // if (pid < 0) {
    //     perror("second fork failed");
    //     exit(EXIT_FAILURE);
    // }
    // if (pid > 0) {  // 第一次的子进程退出
    //     exit(EXIT_SUCCESS);
    // }

    //更改进程的工作路径 1.避免阻止文件系统卸载 安全问题等等
    //将工作目录改为根目录（`/`），因为根目录通常是系统启动后始终存在的文件系统（不会被卸载），这样就不会阻止其他文件系统的卸载操作
    if(nochair == 0)
    chdir("/");

    //  4. 依旧可能与显示器，键盘，stdin，stdout，stderr关联的.
    //  守护进程，不从键盘输入，也不需要向显示器打印
    //  方法1：关闭0,1,2 -- 不推荐
    //  方法2：打开/dev/null, 重定向标准输入，标准输出，标准错误到/dev/null

    if(noclose == 0)
    {
        //读写模式
        int fd = ::open(dev.c_str(),O_RDWR);
        if(fd <0)
        {
            LOG(LogLevel::FATAL) << "open " << dev << " errno";
            exit(OPEN_ERR);
        }
        else
        {
            //dup2用于复制文件描述符的系统调用，常用于重定向标准输入、输出或错误流
            //int dup2(int oldfd, int newfd);
            dup2(fd,0);
            dup2(fd,1);
            dup2(fd,2);
            close(fd);
        }
    }
}


